package com.bottomlord.inject;

import com.bottomlord.functions.ThrowableFunction;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;

import static com.bottomlord.functions.ThrowableFunction.execute;

/**
 * @author ChenYue
 * @date 2021/4/8 11:01
 */
public abstract class AbstractComponentRepository implements ComponentRepository {
    private final Logger log = Logger.getLogger(this.getClass().getName());
    private final Map<String, Object> componentsCache = new LinkedHashMap<>();

    @Override
    @SuppressWarnings("unchecked")
    public <C> C getComponent(String componentName) {
        return (C) this.componentsCache.computeIfAbsent(componentName, this::doGetComponent);
    }

    @Override
    public Set<String> getComponentNames() {
        return this.componentsCache.isEmpty() ? listComponentNames() : this.componentsCache.keySet();
    }

    protected abstract Object doGetComponent(String componentName);

    protected abstract Set<String> listComponentNames();

    /**
     * 通过指定 ThrowableFunction 返回计算结果
     *
     * @param arg              Function's argument
     * @param function         ThrowableFunction
     * @param ignoredException 是否忽略异常
     * @param <R>              返回结果类型
     * @return 返回
     * @see ThrowableFunction#apply(Object)
     */
    protected <T, R> R executeInContext(T arg, ThrowableFunction<T, R> function, boolean ignoredException) {
        R result = null;

        try {
            result = execute(arg, function);
        } catch (Throwable e) {
            if (ignoredException) {
                log.warning(e.getMessage());
            } else {
                throw new RuntimeException(e);
            }
        }

        return result;
    }
}
